package com.example.waterdispenserm2.mo.ttldeep;


import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.aill.androidserialport.SerialPort;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

    public class InductionCookerProtocolDeep {

        // 协议常量 (单位: 微秒)
        private static final int HOST_INTERVAL = 100;          // 主机发送间隔(ms)
        private static final int RESPONSE_DELAY = 4;           // 从机响应延迟(ms)
        private static final int START_BIT_DURATION = 2000;    // 引导码时长(us)
        private static final int BIT1_HIGH_DURATION = 500;     // 1码高电平时间(us)
        private static final int BIT1_LOW_DURATION = 250;      // 1码低电平时间(us)
        private static final int BIT0_HIGH_DURATION = 125;     // 0码高电平时间(us)
        private static final int BIT0_LOW_DURATION = 625;      // 0码低电平时间(us)
        private static final byte ID_CODE = (byte) 0xA5;       // 识别码固定值

        // 段码表 (共阴极数码管)
        private static final byte[] SEGMENT_TABLE = {
                0x3F, // 0
                0x06, // 1
                0x5B, // 2
                0x4F, // 3
                0x66, // 4
                0x6D, // 5
                0x7D, // 6
                0x07, // 7
                0x7F, // 8
                0x6F, // 9
                0x77, // A
                0x7C, // B
                0x39, // C
                0x5E, // D
                0x79, // E
                0x71  // F
        };

        // 按键键值定义
        public static final byte KEY_NONE = 0;
        public static final byte KEY_POWER = 1;
        public static final byte KEY_TIMER = 2;
        public static final byte KEY_DEC = 3;
        public static final byte KEY_INC = 4;
        public static final byte KEY_FUNCTION = 5;
        public static final byte KEY_START = 6;

        // 硬件接口
        private SerialPort mSerialPort;
        private InputStream mInputStream;
        private OutputStream mOutputStream;

        // 线程控制
        private final AtomicBoolean mRunning = new AtomicBoolean(false);
        private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
        private final Handler mMainHandler = new Handler(Looper.getMainLooper());

        // 回调接口
        public interface ProtocolListener {
            void onDisplayUpdate(int digit1, int digit2, int digit3, int digit4, int leds);
            void onKeySent(byte key);
            void onError(String message);
            void onStatusChanged(boolean connected);
            void onLogMessage(String message);
        }
        private ProtocolListener mListener;

        /**
         * 初始化协议处理器
         * @param device 串口设备路径 (如 "/dev/ttyS1")
         * @param baudrate 波特率 (协议为位时序驱动，推荐9600)
         */
        public InductionCookerProtocolDeep(String device, int baudrate) {
            try {
                // 打开串口 (8位数据位，1位停止位，无校验)
                mSerialPort = new SerialPort(new File(device), baudrate, 0);
                mInputStream = mSerialPort.getInputStream();
                mOutputStream = mSerialPort.getOutputStream();

                // 初始设置空闲高电平
                setLineLevel(true);
                log("串口已打开: " + device);

                notifyStatus(true);

            } catch (Exception e) {
                log("串口打开失败: " + e.getMessage());
                notifyError("串口打开失败: " + e.getMessage());
                notifyStatus(false);
            }
        }

        /**
         * 启动通信协议
         * @param listener 协议事件监听器
         */
        public void start(ProtocolListener listener) {
            if (mRunning.get()) return;

            mListener = listener;
            if (mSerialPort == null) {
                notifyError("串口未初始化");
                return;
            }

            mRunning.set(true);
            mExecutor.execute(this::receiveLoop);
            log("协议处理启动");
        }

        /**
         * 停止通信协议
         */
        public void stop() {
            mRunning.set(false);
            mExecutor.shutdownNow();
            log("协议处理停止");

            try {
                if (mInputStream != null) mInputStream.close();
                if (mOutputStream != null) {
                    setLineLevel(true); // 恢复空闲高电平
                    mOutputStream.close();
                }
                if (mSerialPort != null) mSerialPort.close();
            } catch (IOException e) {
                Log.e("Serial", "关闭资源失败", e);
            }

            notifyStatus(false);
        }

        /**
         * 发送按键值到主机
         * @param key 按键键值 (使用KEY_*常量)
         */
        public void sendKey(byte key) {
            if (!mRunning.get() || key == KEY_NONE) return;

            mExecutor.execute(() -> {
                try {
                    log("发送按键: " + key);

                    // 1. 发送引导码 (2ms低电平)
                    sendStartBit();

                    // 2. 发送按键值
                    sendByte(key);

                    // 3. 发送校验码 (按键值取反)
                    sendByte((byte) ~key);

                    // 4. 恢复空闲高电平
                    setLineLevel(true);

                    // 通知发送成功
                    notifyKeySent(key);

                } catch (Exception e) {
                    log("按键发送失败: " + e.getMessage());
                    notifyError("按键发送失败: " + e.getMessage());
                }
            });
        }

        // ================= 核心协议处理逻辑 ================= //
        private void receiveLoop() {
            log("开始接收循环");
            while (mRunning.get()) {
                try {
                    // 1. 检测并读取引导码 (2ms低电平)
                    if (!detectStartBit()) {
                        Thread.sleep(1); // 避免CPU忙等待
                        continue;
                    }

                    // 2. 接收主机数据包 (7字节)
                    byte[] packet = receivePacket(7);
                    if (packet == null) continue;

                    // 3. 校验数据包
                    if (!validatePacket(packet)) {
                        log("数据校验失败");
                        notifyError("数据校验失败");
                        continue;
                    }

                    // 4. 处理显示数据
                    processDisplayData(packet);

                    // 5. 延时4ms后准备响应
                    Thread.sleep(RESPONSE_DELAY);

                } catch (InterruptedException e) {
                    break; // 正常退出
                } catch (Exception e) {
                    log("接收错误: " + e.getMessage());
                    notifyError("接收错误: " + e.getMessage());
                }
            }
            log("接收循环结束");
        }

        private byte[] receivePacket(int length) throws IOException {
            byte[] packet = new byte[length];
            for (int i = 0; i < length; i++) {
                packet[i] = receiveByte();
            }
            return packet;
        }

        private byte receiveByte() throws IOException {
            byte value = 0;
            for (int i = 0; i < 8; i++) {
                // 高位在前
                value <<= 1;
                if (receiveBit()) {
                    value |= 1;
                }
            }
            return value;
        }

        private boolean receiveBit() throws IOException {
            // 等待上升沿 (低->高)
            long start = System.nanoTime();
            while (readLineLevel() == 0) {
                if (System.nanoTime() - start > 1_000_000 * 10) { // 10ms超时
                    throw new IOException("等待上升沿超时");
                }
            }

            // 测量高电平持续时间
            long highStart = System.nanoTime();
            while (readLineLevel() == 1) {
                // 等待高电平结束
            }
            long highDuration = (System.nanoTime() - highStart) / 1000; // us

            // 根据高电平时间判断位值
            return Math.abs(highDuration - BIT1_HIGH_DURATION) <
                    Math.abs(highDuration - BIT0_HIGH_DURATION);
        }

        // ================= 数据解析方法 ================= //
        private boolean validatePacket(byte[] packet) {
            // 检查识别码
            if (packet[0] != ID_CODE) return false;

            // 计算校验和 (前6字节求和取低8位)
            int checksum = 0;
            for (int i = 0; i < 6; i++) {
                checksum += packet[i] & 0xFF;
            }
            return (byte) (checksum & 0xFF) == packet[6];
        }

        private void processDisplayData(byte[] packet) {
            // 解析数码管显示值
            int digit1 = decodeDigit(packet[1]); // 千位
            int digit2 = decodeDigit(packet[2]); // 百位
            int digit3 = decodeDigit(packet[3]); // 十位
            int digit4 = decodeDigit(packet[4]); // 个位

            // LED状态 (packet[5]的每个bit代表一个LED)
            int leds = packet[5] & 0xFF;

            log(String.format("收到数据: %02X %02X %02X %02X %02X %02X %02X",
                    packet[0], packet[1], packet[2], packet[3], packet[4], packet[5], packet[6]));

            // 回调显示更新
            notifyDisplayUpdate(digit1, digit2, digit3, digit4, leds);
        }

        private int decodeDigit(byte segmentCode) {
            for (int i = 0; i < SEGMENT_TABLE.length; i++) {
                if (SEGMENT_TABLE[i] == (segmentCode & 0xFF)) {
                    return i;
                }
            }
            return -1; // 未知显示
        }

        // ================= 硬件控制方法 ================= //
        private void setLineLevel(boolean high) {
            try {
                // TTL电平控制：高电平=1，低电平=0
                mOutputStream.write(high ? 0xFF : 0x00);
                mOutputStream.flush();
            } catch (IOException e) {
                log("电平设置失败: " + e.getMessage());
                notifyError("电平设置失败: " + e.getMessage());
            }
        }

        private boolean detectStartBit() {
            try {
                long startTime = System.nanoTime();

                // 等待低电平开始
                while (readLineLevel() == 1) {
                    if (System.nanoTime() - startTime > 10_000_000) { // 10ms超时
                        return false;
                    }
                    Thread.sleep(0, 1000); // 短暂等待
                }

                // 验证低电平持续时间
                long lowStart = System.nanoTime();
                while (readLineLevel() == 0) {
                    // 等待低电平结束
                }
                long duration = (System.nanoTime() - lowStart) / 1000; // us

                // 检查是否在引导码时间范围内
                return duration >= (START_BIT_DURATION * 0.8) &&
                        duration <= (START_BIT_DURATION * 1.2);

            } catch (Exception e) {
                log("引导码检测失败: " + e.getMessage());
                return false;
            }
        }

        private int readLineLevel() throws IOException {
            return mInputStream.read(); // 返回0(低电平)或1(高电平)
        }

        private void sendStartBit() {
            setLineLevel(false);
            sleepMicros(START_BIT_DURATION);
        }

        private void sendByte(byte data) {
            for (int i = 7; i >= 0; i--) { // 高位在前
                boolean bit = ((data >> i) & 1) == 1;
                sendBit(bit);
            }
        }

        private void sendBit(boolean isOne) {
            // 发送高电平部分
            setLineLevel(true);
            sleepMicros(isOne ? BIT1_HIGH_DURATION : BIT0_HIGH_DURATION);

            // 发送低电平部分
            setLineLevel(false);
            sleepMicros(isOne ? BIT1_LOW_DURATION : BIT0_LOW_DURATION);
        }

        // ================= 辅助方法 ================= //
        private void sleepMicros(int micros) {
            try {
                long nanos = micros * 1000L;
                long millis = nanos / 1_000_000;
                int remainingNanos = (int) (nanos % 1_000_000);
                Thread.sleep(millis, remainingNanos);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        private void log(String message) {
            Log.d("Protocol", message);
            if (mListener != null) {
                mMainHandler.post(() -> mListener.onLogMessage(message));
            }
        }

        private void notifyDisplayUpdate(int d1, int d2, int d3, int d4, int leds) {
            if (mListener != null) {
                mMainHandler.post(() ->
                        mListener.onDisplayUpdate(d1, d2, d3, d4, leds));
            }
        }

        private void notifyKeySent(byte key) {
            if (mListener != null) {
                mMainHandler.post(() -> mListener.onKeySent(key));
            }
        }

        private void notifyError(String message) {
            if (mListener != null) {
                mMainHandler.post(() -> mListener.onError(message));
            }
        }

        private void notifyStatus(boolean connected) {
            if (mListener != null) {
                mMainHandler.post(() -> mListener.onStatusChanged(connected));
            }
        }


}
